Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Use can_hold instead of can_reserve in fn hold #12004

Closed
wants to merge 17 commits into from

Conversation

KiChjang
Copy link
Contributor

Per title, also tries to use safe math.

It seems to me that #8454 really intended the code to be calling InspectHold::can_hold rather than ReservableCurrency::can_reserve, but perhaps due to merge conflicts, the can_hold call has been clobbered by can_reserve.

Part of #8285 and paritytech/polkadot-sdk#327.

@KiChjang KiChjang added A0-please_review Pull request needs code review. B0-silent Changes should not be mentioned in any release notes C1-low PR touches the given topic and has a low impact on builders. D3-trivial 🧸 PR contains trivial changes in a runtime directory that do not require an audit labels Aug 10, 2022
@shawntabrizi
Copy link
Member

Test?

Copy link
Member

@shawntabrizi shawntabrizi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks sensible to me

@gavofyork
Copy link
Member

No test?

@stale
Copy link

stale bot commented Sep 14, 2022

Hey, is anyone still working on this? Due to the inactivity this issue has been automatically marked as stale. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the A5-stale Pull request did not receive any updates in a long time. No review needed at this stage. Close it. label Sep 14, 2022
@stale stale bot removed the A5-stale Pull request did not receive any updates in a long time. No review needed at this stage. Close it. label Sep 27, 2022
})?;
Ok(())
ensure!(
<Self as fungible::InspectHold<T::AccountId>>::can_hold(who, amount),
Copy link
Contributor Author

@KiChjang KiChjang Sep 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, after writing unit tests, I found out that there is a difference between can_reserve and can_hold: the latter ensures that the reserved/held amount doesn't make the free balance go below the existential deposit. Should we still continue using can_hold here then? Or should we change can_hold to match the semantics of can_reserve?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we change can_hold what that mess up any existing code using can_hold / what are the tradeoffs?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We want people to be able to use fungible traits instead of Currency in the future. See #8285 and #8453. We currently use Currency traits everywhere, and we'd like to change that.

Copy link
Contributor

@sam0x17 sam0x17 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me once we have a definitive answer about the can_hold / can_reserve thing

@kianenigma
Copy link
Contributor

7a6db84 Looks good.

@stale
Copy link

stale bot commented Nov 10, 2022

Hey, is anyone still working on this? Due to the inactivity this issue has been automatically marked as stale. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the A5-stale Pull request did not receive any updates in a long time. No review needed at this stage. Close it. label Nov 10, 2022
@stale stale bot removed the A5-stale Pull request did not receive any updates in a long time. No review needed at this stage. Close it. label Nov 15, 2022
Copy link
Member

@gavofyork gavofyork left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

holding/reserving should never kill an account, so adding the keep_alive arg doesn't make sense here.

@paritytech-processbot
Copy link

Rebased

As per this comment: #12004 (review)

This reverts commit 7a6db84.
@ruseinov ruseinov self-assigned this Nov 29, 2022
@ruseinov
Copy link
Contributor

ruseinov commented Nov 29, 2022

Would appreciate input in terms of logic soundness for can_reserve.

The important differences between the current code and the last review:

  1. keep_alive for can_hold has been reverted as we should never reap the account on hold.
  2. ensure_can_withdraw has been removed from can_reserve as it is a subset of the new logic.
  3. can_reserve now takes ExistentialDeposit into account to make sure there is no overdraft.
  4. reserve is now enforcing can_reserve.

What this basically means is that can_reserve basically replicates can_hold logic in terms of balance assumptions.

@paritytech-cicd-pr
Copy link

The CI pipeline was cancelled due to failure one of the required jobs.
Job name: test-linux-stable
Logs: https://gitlab.parity.io/parity/mirrors/substrate/-/jobs/2110851

@ruseinov
Copy link
Contributor

ruseinov commented Dec 3, 2022

A bit stuck on this one while fixing other pallets, duplicating my post in FRAME Element room for posterity:

Basically, after introducing the change to can_reserve and reserve we have to reserve here

.and_then(|_| T::Currency::reserve(contract, *amount));
taking into account the ED. .and_then(|_| T::Currency::reserve(contract, *amount - ED)); . I'm not sure it's the correct behaviour. Any insight would be much appreciated.
This also then breaks the refund logic.

@ruseinov
Copy link
Contributor

ruseinov commented Dec 5, 2022

This breaks the current implementation of contracts pallet, currently blocked until @athei figures out how we want to go about those changes.

@ruseinov
Copy link
Contributor

ruseinov commented Dec 6, 2022

Additional notes:

Modify pallet-balances to take care of the below:

having a non-zero reserved balance should imply a consumer ref.
anything which alters the reserved balance should inc consumer refs when it goes from is_zero() -> !is_zero() and dec the consumer ref when the opposite is
true.

But I'm not sure how this can solve the contracts issue. Because if we only transfer the ED - it will be unreserved and therefore there won't be a consumer ref.

@athei
Copy link
Member

athei commented Dec 6, 2022

But I'm not sure how this can solve the contracts issue. Because if we only transfer the ED - it will be unreserved and therefore there won't be a consumer ref.

pallet-contracts transfers at least the ED on contract instantiation and then reserves it.

@ruseinov
Copy link
Contributor

ruseinov commented Dec 8, 2022

But I'm not sure how this can solve the contracts issue. Because if we only transfer the ED - it will be unreserved and therefore there won't be a consumer ref.

pallet-contracts transfers at least the ED on contract instantiation and then reserves it.

Yeah, but we can't reserve the ED anymore due to the changes in can_reserve (which is called in reserve). Or rather we can, but we still need to have at least ED in free balance.

@athei
Copy link
Member

athei commented Dec 8, 2022

I thought a while about this any my preferred solution would be that a contract can act as a sufficient for an account. It is a consumer because it depends on the existence of its account (and by extension its balance). But it is also a provider because it takes storage deposit which covers both the existential deposit and the data structures within pallet-contracts.

Up until now this was achieved by transferring this deposit to the contract and reserving it there. This does no longer work with this PR as the existential deposit must be free balance. This issue arises because pallet-contracts is a sufficient only indirectly (by enforcing a certain balance). I think that should change and pallet-contracts should call System::inc_sufficients directly when creating a contract. The workflow I imagine is as as follows:

  1. Contract is about to be instantiated
  2. System::inc_sufficients(contract)
  3. Currency::transfer(caller, contract, storage_deposit)
  4. Currency::reserve(contract, storage_deposit)

Step 4. is where it currently fails because we cannot reserve all the contract's balance as some of it needs to be free. We could work around this by partly leaving some balance free and creating a consumer to prevent the balance to be send away. However, I think that feels a bit weird when part of the deposit is free and some is reserved. Additionally, a storage migration is needed that changes all contract's accounts to have some free balance. This is why I suggest changing the can_reserve logic to the following which would allow the above workflow without a storage migration:

Allow reserving the ED (as it was the case before this PR) but remove the provider created by pallet-balances when doing so. If this would reap the account (because there is no other provider) we won`t allow the reserve because we never want the reserve to kill an account. Not sure if this is a sound solution. Need some more thinking and debate.

Another suggestion made by @gavofyork is to automatically add a consumer to an account whenever there is a non zero reserved balance. This would also work for contracts as we could send part of the initial balance as free balance as mentioned above. However, this also needs this big storage migration of all existing accounts with reserved balance.

@stale
Copy link

stale bot commented Jan 14, 2023

Hey, is anyone still working on this? Due to the inactivity this issue has been automatically marked as stale. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the A5-stale Pull request did not receive any updates in a long time. No review needed at this stage. Close it. label Jan 14, 2023
@ruseinov
Copy link
Contributor

This has been stale for a while as we did not reach consensus on how to proceed with this as far as I understand.
This should fix it: #12951

@stale stale bot removed the A5-stale Pull request did not receive any updates in a long time. No review needed at this stage. Close it. label Jan 17, 2023
@stale
Copy link

stale bot commented Feb 17, 2023

Hey, is anyone still working on this? Due to the inactivity this issue has been automatically marked as stale. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the A3-stale label Feb 17, 2023
@gavofyork
Copy link
Member

Superseded by #12951.

@gavofyork gavofyork closed this Feb 22, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
A0-please_review Pull request needs code review. A3-stale B0-silent Changes should not be mentioned in any release notes C1-low PR touches the given topic and has a low impact on builders. D3-trivial 🧸 PR contains trivial changes in a runtime directory that do not require an audit
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

8 participants